using Circus.CodeEditor;
using Circus.Syntax;
using Circus.Syntax.CodeCompletion;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace Circus.CodeEditor.CodeCompletion
{
	[DesignerCategory("Code"), DesignTimeVisible(false), ToolboxItem(false)]
	public class CompletionListBox : ListBox
	{
		internal class ListboxItem
		{
			public string String;
			public int Index;
			public ListboxItem(string s, int index)
			{
				this.String = s;
				this.Index = index;
			}
			public override string ToString()
			{
				return this.String;
			}
		}
		private bool filtered = false;
		private string filter = string.Empty;
		private int priority = -1;
		private ICodeCompletionProvider provider;
		private List<CodeCompletionColumn> columns;
		private IList<int> columnWidths;
		private int itemWidth = 0;
		private Painter painter;
		private HtmlSyntaxPaint syntaxPaint;
		private EventHandler updateSize;
		private ImageList images;
		private bool focusMode = false;
		private Keys[] navKeys = new Keys[]
		{
			Keys.Up,
			Keys.Down,
			Keys.Prior,
			Keys.Next
		};
		public List<CodeCompletionColumn> Columns
		{
			get
			{
				return this.columns;
			}
		}
		public bool Filtered
		{
			get
			{
				return this.filtered;
			}
			set
			{
				if (this.filtered != value)
				{
					this.filtered = value;
					this.OnFilteredChanged();
				}
			}
		}
		public string Filter
		{
			get
			{
				return this.filter;
			}
			set
			{
				if (this.filter != value)
				{
					this.filter = value;
					this.OnFilterChanged();
				}
			}
		}
		public int Priority
		{
			get
			{
				return this.priority;
			}
			set
			{
				if (this.priority != value)
				{
					this.priority = value;
					this.OnPriorityChanged();
				}
			}
		}
		public int ColumnCount
		{
			get
			{
				return this.columns.Count;
			}
		}
		public ICodeCompletionProvider Provider
		{
			get
			{
				return this.provider;
			}
			set
			{
				if (this.provider != value)
				{
					this.provider = value;
					this.ProviderChanged();
				}
			}
		}
		public int ItemWidth
		{
			get
			{
				return this.itemWidth;
			}
		}
		public ImageList Images
		{
			get
			{
				return this.images;
			}
			set
			{
				if (this.images != value)
				{
					this.images = value;
					this.OnImagesChanged();
				}
			}
		}
		public Keys[] NavKeys
		{
			get
			{
				return this.navKeys;
			}
		}
		public EventHandler UpdateSize
		{
			get
			{
				return this.updateSize;
			}
			set
			{
				this.updateSize = value;
			}
		}
		public override int SelectedIndex
		{
			get
			{
				return base.SelectedIndex;
			}
			set
			{
				bool flag = this.focusMode;
				try
				{
					base.SelectedIndex = value;
				}
				finally
				{
					this.focusMode = flag;
				}
			}
		}
		public bool FocusMode
		{
			get
			{
				return this.focusMode;
			}
			set
			{
				if (this.focusMode != value)
				{
					this.focusMode = value;
					base.Invalidate();
				}
			}
		}
		private int MeasureWidth(string text, FontStyle style)
		{
			int result;
			if (text != null)
			{
			    this.painter.fontStyle = style;
			    StringItemInfo[] colorData = null;
				this.syntaxPaint.PrepareData(0, style, ref text, ref colorData);
				result = this.syntaxPaint.MeasureLine(text, colorData, 0, text.Length);
			}
			else
			{
				result = 0;
			}
			return result;
		}
		private void DrawColumn(Rectangle rect, string text, Color foreColor, FontStyle style)
		{
			if (text != null)
			{
				this.painter.TextColor = foreColor;
				this.painter.Opaque = false;
			    this.painter.fontStyle = style;
			    StringItemInfo[] colorData = null;
				this.syntaxPaint.PrepareData(0, style, ref text, ref colorData);
				this.syntaxPaint.DrawLine(0, text, colorData, rect.Location, rect);
			}
		}
		protected virtual void ProviderChanged()
		{
			base.BeginUpdate();
			try
			{
				base.Items.Clear();
				this.columnWidths.Clear();
				this.itemWidth = 0;
				this.syntaxPaint.Provider = this.provider;
				if (this.provider != null)
				{
					for (int i = 0; i < this.provider.Count; i++)
					{
						string name = this.provider.GetName(i);
						if (this.IsFiltered(name, this.provider.GetPriority(i)))
						{
							base.Items.Add(new CompletionListBox.ListboxItem(name, i));
						}
					}
					for (int i = 0; i < this.provider.ColumnCount; i++)
					{
						int num = EditConsts.DefaultColumnSeparator;
						if (this.provider.ColumnVisible(i))
						{
							CodeCompletionColumn codeCompletionColumn = (i < this.columns.Count) ? this.GetColumn(i) : null;
							for (int j = 0; j < this.provider.Count; j++)
							{
								if (this.IsFiltered(this.provider.GetName(j), this.provider.GetPriority(j)))
								{
									num = Math.Max(num, this.MeasureWidth(this.provider.GetColumnText(j, i), (codeCompletionColumn != null) ? codeCompletionColumn.FontStyle : FontStyle.Regular));
								}
							}
							num += EditConsts.DefaultColumnSeparator;
						}
						this.itemWidth += num;
						this.columnWidths.Add(num);
					}
				}
				this.UpdateControlSize();
			}
			finally
			{
				base.EndUpdate();
			}
		}
		protected override void OnKeyDown(KeyEventArgs e)
		{
			if (Array.IndexOf<Keys>(EditConsts.NavKeys, e.KeyCode) >= 0 && Array.IndexOf<Keys>(this.navKeys, e.KeyCode) < 0)
			{
				e.Handled = (e.KeyCode != Keys.Tab);
			}
			base.OnKeyDown(e);
		}
		protected override void OnSelectedIndexChanged(EventArgs e)
		{
			base.OnSelectedIndexChanged(e);
			this.FocusMode = false;
		}
		protected virtual bool IsFilteredString(string s)
		{
			return !this.Filtered || this.filter == null || this.filter == string.Empty || s.StartsWith(this.filter, StringComparison.OrdinalIgnoreCase);
		}
		protected virtual bool IsFilteredPriority(int priority)
		{
			return this.priority == -1 || priority == this.priority;
		}
		protected virtual bool IsFiltered(string s, int priority)
		{
			return this.IsFilteredString(s) && this.IsFilteredPriority(priority);
		}
		protected void UpdateControlSize()
		{
			int num = this.painter.FontHeight + EditConsts.DefaultRowSeparator;
			if (this.images != null)
			{
				num = Math.Max(num, this.images.ImageSize.Height);
			}
			this.ItemHeight = num;
			base.HorizontalExtent = ((this.provider != null && this.provider.ColumnCount != 0) ? this.itemWidth : ((this.images != null) ? (this.images.ImageSize.Width + EditConsts.DefaultColumnSeparator) : 0));
			if (this.UpdateSize != null)
			{
				this.UpdateSize(this, EventArgs.Empty);
			}
		}
		protected override void OnMeasureItem(MeasureItemEventArgs e)
		{
			base.OnMeasureItem(e);
			if (this.images != null)
			{
				e.ItemHeight = Math.Max(e.ItemHeight, this.images.ImageSize.Height);
			}
		}
		protected override void OnDrawItem(DrawItemEventArgs e)
		{
			int index = this.GetIndex(e.Index);
			if (this.provider == null || index < 0 || index >= this.provider.Count)
			{
				base.OnDrawItem(e);
			}
			else
			{
				bool flag = (e.State & DrawItemState.Disabled) != DrawItemState.None;
				bool flag2 = (e.State & DrawItemState.Focus) != DrawItemState.None && (e.State & DrawItemState.NoFocusRect) == DrawItemState.None;
				bool flag3 = (e.State & DrawItemState.Selected) != DrawItemState.None;
				Size size = (this.images != null) ? new Size(this.images.ImageSize.Width + EditConsts.DefaultColumnSeparator, this.images.ImageSize.Height) : new Size(0, 0);
				if (this.images != null)
				{
					int imageIndex = this.provider.GetImageIndex(index);
					if (imageIndex >= 0 && imageIndex < this.images.Images.Count)
					{
						this.images.Draw(e.Graphics, e.Bounds.Left, e.Bounds.Top + (e.Bounds.Height - size.Height) / 2, imageIndex);
					}
					e.Graphics.TranslateTransform((float)size.Width, 0f);
				}
				if (!this.focusMode || !flag3)
				{
					e.DrawBackground();
				}
				else
				{
					flag3 = false;
					using (Brush brush = new SolidBrush(this.BackColor))
					{
						e.Graphics.FillRectangle(brush, e.Bounds);
					}
				}
				if (flag2)
				{
					e.DrawFocusRectangle();
				}
				int num = e.Bounds.Left + size.Width + EditConsts.DefaultColumnSeparator;
				this.painter.BeginPaint(e.Graphics);
				try
				{
					for (int i = 0; i < this.provider.ColumnCount; i++)
					{
						CodeCompletionColumn codeCompletionColumn = (i < this.columns.Count) ? this.GetColumn(i) : null;
						if ((codeCompletionColumn == null || codeCompletionColumn.Visible) && this.provider.ColumnVisible(i))
						{
							Color foreColor = (codeCompletionColumn != null) ? codeCompletionColumn.ForeColor : this.ForeColor;
							int num2 = this.columnWidths[i];
							Rectangle rect = new Rectangle(num, e.Bounds.Top, num2, e.Bounds.Height);
							if (flag)
							{
								foreColor = EditConsts.DefaultDisabledForeColor;
							}
							else
							{
								if (flag3)
								{
									foreColor = EditConsts.DefaultHighlightForeColor;
								}
							}
							this.DrawColumn(rect, this.provider.GetColumnText(index, i), foreColor, (codeCompletionColumn != null) ? codeCompletionColumn.FontStyle : FontStyle.Regular);
							num += num2;
						}
					}
				}
				finally
				{
					this.painter.EndPaint();
				}
			}
		}
		protected override void OnFontChanged(EventArgs e)
		{
			base.OnFontChanged(e);
			this.painter.Clear();
		    this.painter.font = this.Font;
		    this.UpdateControlSize();
		}
		protected virtual void OnImagesChanged()
		{
			this.UpdateControlSize();
		}
		protected virtual void OnFilteredChanged()
		{
			this.ResetContent(0);
		}
		protected virtual void OnFilterChanged()
		{
			if (this.Filtered)
			{
				this.ResetContent(0);
			}
		}
		protected virtual void OnPriorityChanged()
		{
			this.ResetContent(0);
		}
		public CompletionListBox()
		{
            this.columns = new List<CodeCompletionColumn>();
			this.columnWidths = new List<int>();
			this.painter = new Painter();
		    this.painter.font = this.Font;
		    this.syntaxPaint = new HtmlSyntaxPaint(this.painter, null);
			this.DrawMode = DrawMode.OwnerDrawVariable;
			base.BorderStyle = BorderStyle.None;
			base.HorizontalScrollbar = true;
			base.Sorted = true;
			this.BackColor = Consts.DefaultPopupBackColor;
		}
		public int GetIndex()
		{
			return this.focusMode ? -1 : this.GetIndex(this.SelectedIndex);
		}
		public int GetIndex(int index)
		{
			int result;
			if ((!this.Filtered && this.Priority == -1 && !base.Sorted) || index < 0 || index >= base.Items.Count)
			{
				result = index;
			}
			else
			{
				result = ((CompletionListBox.ListboxItem)base.Items[index]).Index;
			}
			return result;
		}
		public void ResetContent(int index)
		{
			base.BeginUpdate();
			try
			{
				this.ResetContent();
				if (index >= 0 && index < base.Items.Count)
				{
					this.SelectedIndex = index;
				}
			}
			finally
			{
				base.EndUpdate();
			}
		}
		public void ResetContent()
		{
			this.ProviderChanged();
		}
		public CodeCompletionColumn GetColumn(int index)
		{
			return this.columns[index];
		}
		public void ClearColumns()
		{
			this.columns.Clear();
		}
		public CodeCompletionColumn AddColumn()
		{
			CodeCompletionColumn codeCompletionColumn = new CodeCompletionColumn();
			this.columns.Add(codeCompletionColumn);
			return codeCompletionColumn;
		}
		public CodeCompletionColumn InsertColumn(int index)
		{
			CodeCompletionColumn codeCompletionColumn = new CodeCompletionColumn();
			this.columns.Insert(index, codeCompletionColumn);
			return codeCompletionColumn;
		}
		public void RemoveColumnAt(int index)
		{
			this.columns.RemoveAt(index);
		}
		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				if (this.syntaxPaint != null)
				{
					this.syntaxPaint.Dispose();
					this.syntaxPaint = null;
				}
			}
			base.Dispose(disposing);
		}
	}
}
